Option Explicit

'################################################################
' Discriptor
' DFFilter 条件定义接口实现
' 非 Boolean 型单列的 [in] 比较
'################################################################

Implements IDFFilterColCondition

'################################################################
' Field
'################################################################
' 原始列，可以是真实列 DFFilterSingleCol 或者其他包装类型
Private fieldMainCol As IDFFilterCol

' 左比较参数
Private fieldLeftCol As IDFFilterCol

' 右比较参数
Private fieldRightCol As IDFFilterCol

'################################################################
' Constructor
'################################################################
Private Sub Class_Initialize()
End Sub

Private Sub Class_Terminate()
End Sub

'################################################################
' Init
'################################################################
' @param mainCol 主计算列
'            不能是 Boolean 型
' @param leftCol 左比较列，类型应该和 col 相容
' @param rightCol 右比较列，类型应该和 col 相容
'                   INT, DECIMAL 可以相容
'                   DF_DATE, DF_TIME, DF_TIMESTAMP 可以相容
Public Sub Init(ByRef mainCol As IDFFilterCol, ByRef leftCol As IDFFilterCol, ByRef rightCol As IDFFilterCol)
    ' 1. 检查参数
    ' 1.1 列不能是空
    If mainCol Is Nothing Then
        Err.Raise 10001, Description:="parameter mainCol must be not nothing"
        Exit Sub
    End If
    If leftCol Is Nothing Then
        Err.Raise 10001, Description:="parameter leftCol must be not nothing"
        Exit Sub
    End If
    If rightCol Is Nothing Then
        Err.Raise 10001, Description:="parameter rightCol must be not nothing"
        Exit Sub
    End If

    ' 1.2 列不能是 Boolean 型
    If mainCol.ColType Is DF_DataType.DF_BOOLEAN Then
        Err.Raise 10312, Description:="DF_DataType.DF_BOOLEAN [mainCol] column can not be used in Between-condition"
        Exit Sub
    End If
    If leftCol.ColType Is DF_DataType.DF_BOOLEAN Then
        Err.Raise 10312, Description:="DF_DataType.DF_BOOLEAN [leftCol] column can not be used in Between-condition"
        Exit Sub
    End If
    If rightCol.ColType Is DF_DataType.DF_BOOLEAN Then
        Err.Raise 10312, Description:="DF_DataType.DF_BOOLEAN [rightCol] column can not be used in Between-condition"
        Exit Sub
    End If

    ' 1.3 列的类型不能是聚合列或组合式聚合列
    If mainCol.isAggregateCol Then
        Err.Raise 10311, Description:="Aggregate Column Parameter [mainCol] can not use in condition"
        Exit Sub
    End If
    If leftCol.isAggregateCol Then
        Err.Raise 10311, Description:="Aggregate Column Parameter [leftCol] can not use in condition"
        Exit Sub
    End If
    If rightCol.isAggregateCol Then
        Err.Raise 10311, Description:="Aggregate Column Parameter [rightCol] can not use in condition"
        Exit Sub
    End If

    ' 2. 检查 left, right 的类型
    Dim mainType As DF_DataType
    Dim leftType As DF_DataType
    mainType = mainCol.ColType
    leftType = leftCol.ColType

    If mainType <> leftType Then
        If (mainType = DF_DataType.DF_INT Or mainType = DF_DataType.DF_DECIMAL) And _
        (leftType = DF_DataType.DF_INT Or leftType = DF_DataType.DF_DECIMAL) Then
            ' 如果两者的类型是 INT 或 DECIMAL 则类型相容
            ' noop
        ElseIf (mainType = DF_DataType.DF_DATE Or mainType = DF_DataType.DF_TIME Or mainType = DF_DataType.DF_TIMESTAMP) And _
            (leftType = DF_DataType.DF_DATE Or leftType = DF_DataType.DF_TIME Or leftType = DF_DataType.DF_TIMESTAMP) Then
            ' noop
                ' 如果两者的类型是 DF_DATE, DF_TIME, DF_TIMESTAMP 可以相容
        Else
            Err.Raise 10302, Description:="parameter type of mainCol and leftCol is not same: mainCol Type=" & _
                            DFHelper.getDataTypeName(mainType) & _
                            ", leftCol Type=" & DFHelper.getDataTypeName(leftType)
            Exit Sub
        End If
    End If

    Dim rightType As DF_DataType
    rightType = rightCol.ColType

    If mainType <> rightType Then
        If (mainType = DF_DataType.DF_INT Or mainType = DF_DataType.DF_DECIMAL) And _
        (rightType = DF_DataType.DF_INT Or rightType = DF_DataType.DF_DECIMAL) Then
            ' 如果两者的类型是 INT 或 DECIMAL 则类型相容
            ' noop
        ElseIf (mainType = DF_DataType.DF_DATE Or mainType = DF_DataType.DF_TIME Or mainType = DF_DataType.DF_TIMESTAMP) And _
            (rightType = DF_DataType.DF_DATE Or rightType = DF_DataType.DF_TIME Or rightType = DF_DataType.DF_TIMESTAMP) Then
            ' noop
                ' 如果两者的类型是 DF_DATE, DF_TIME, DF_TIMESTAMP 可以相容
        Else
            Err.Raise 10302, Description:="parameter type of mainCol and rightCol is not same: mainCol Type=" & _
                            DFHelper.getDataTypeName(mainType) & _
                            ", rightCol Type=" & DFHelper.getDataTypeName(rightType)
            Exit Sub
        End If
    End If

    ' 3. 保存参数
    Set fieldMainCol = mainCol
    Set fieldLeftCol = leftCol
    Set fieldRightCol = rightCol
End Sub

'################################################################
' Function
'################################################################
' 检查 DFFilter 的活动行的数据是否符合规则
' 外部不应该主动调用
Public Function IDFFilterColCondition_unsafeCheckActiveRowVal() As Boolean
    ' 计算当前列的结果
    Dim mainComputedVal As Variant
    mainComputedVal = fieldMainCol.unsafeGetActiveRowVal()

    If mainComputedVal < fieldLeftCol.unsafeGetActiveRowVal() Then
        IDFFilterColCondition_unsafeCheckActiveRowVal = False
        Exit Sub
    End If

    If mainComputedVal > fieldRightCol.unsafeGetActiveRowVal() Then
        IDFFilterColCondition_unsafeCheckActiveRowVal = False
        Exit Sub
    End If

    IDFFilterColCondition_unsafeCheckActiveRowVal = True
End Function

' 返回当前条件是不是只使用了一个 Filter
Public Function IDFFilterColCondition_isUseSingleFilter() As Boolean
    ' 唯一返回 True 的组合
    ' 都不是字面量列，列的 Filter 都不是 Nothing，并且 Filter 相同
    Dim isNotAllLiteralCol As Boolean
    isNotAllLiteralCol = False
    Dim f As DFFilter

    If Not fieldLeftCol.isLiteralCol Then
        isNotAllLiteralCol = True
        If fieldLeftCol.Filter Is Nothing Then
            ' 如果某个非字面量列使用 Filter 是多个，则立刻结束
            IDFFilterColCondition_isUseSingleFilter = False
            Exit Function
        End If

        ' 如果是第一次发现一个非字面量列，则保存这个列的 DFFilter
        Set f = fieldLeftCol.Filter
    End If

    If Not fieldRightCol.isLiteralCol Then
        isNotAllLiteralCol = True
        If fieldRightCol.Filter Is Nothing Then
            ' 如果某个非字面量列使用 Filter 是多个，则立刻结束
            IDFFilterColCondition_isUseSingleFilter = False
            Exit Function
        End If

        If f Is Nothing Then
            ' 如果是第一次发现一个非字面量列，则保存这个列的 DFFilter
            Set f = fieldRightCol.Filter
        Else
            ' 如果是第 N 次发现一个非字面量列，则进行比较
            If Not f Is fieldRightCol.Filter Then
                IDFFilterColCondition_isUseSingleFilter = False
                Exit Function
            End If
        End If
    End If

    If Not fieldMainCol.isLiteralCol Then
        isNotAllLiteralCol = True
        If fieldMainCol.Filter Is Nothing Then
            ' 如果某个非字面量列使用 Filter 是多个，则立刻结束
            IDFFilterColCondition_isUseSingleFilter = False
            Exit Function
        End If

        ' 如果是第一次发现一个非字面量列，则不需要处理
        ' 如果是第 N 次发现一个非字面量列，则进行比较
        If Not f Is Nothing Then
            If Not f Is fieldMainCol.Filter Then
                IDFFilterColCondition_isUseSingleFilter = False
                Exit Function
            End If
        End If
    End If

    IDFFilterColCondition_isUseSingleFilter = isNotAllLiteralCol
End Function

' 返回当前条件中是否使用了 Filter
' 因为存在如: And 1=1 这样的全字面量条件
Public Function IDFFilterColCondition_isUseFilter() As Boolean
    ' 只要 main, left, right 中有一个不是字面量，则这个条件就是用了 Filter
    IDFFilterColCondition_isUseFilter = (Not fieldMainCol.isLiteralCol) Or _
                                        (Not fieldLeftCol.isLiteralCol) Or _
                                        (Not fieldRightCol.isLiteralCol)
End Function

' 获取当前条件中使用的所有 Filter
' @return HashSet<DFFilter>
Public Function IDFFilterColCondition_getAllFilters() As ISet
    Set IDFFilterColCondition_getAllFilters = UtilsSet.createHashSet
    IDFFilterColCondition_getAllFilters.MergeSet fieldMainCol.getAllFilters
    IDFFilterColCondition_getAllFilters.MergeSet fieldLeftCol.getAllFilters
    IDFFilterColCondition_getAllFilters.MergeSet fieldRightCol.getAllFilters
End Function

' 检查当前条件使用的 DFFilter 是否和指定的 DFFilter 相同
' 如果条件中使用了多个 Filter，则返回 False
' 如果是全字面量列，则返回 False
Public Function IDFFilterColCondition_isSameFilter(ByRef filter As DFFilter) As Boolean
    ' 返回 True 的条件
    ' 不全是字面量列
    ' 非字面量的 isSameFilter 方法检查结果全部是 True

    ' 检查时，需要忽略其中的字面量列
    Dim isNotAllLiteralCol As Boolean
    isNotAllLiteralCol = False

    ' 检查左列
    If Not fieldLeftCol.isLiteralCol Then
        isNotAllLiteralCol = True
        ' 如果左列的 isSameFilter 结果已经是 False，则立刻结束
        If fieldLeftCol.isSameFilter(filter) = False Then
            IDFFilterColCondition_isSameFilter = False
            Exit Function
        End If
    End If

    ' 检查右列
    If Not fieldRightCol.isLiteralCol Then
        isNotAllLiteralCol = True
        ' 如果右列的 isSameFilter 结果已经是 False，则立刻结束
        If fieldRightCol.isSameFilter(filter) = False Then
            IDFFilterColCondition_isSameFilter = False
            Exit Function
        End If
    End If

    ' 检查主列
    If Not fieldMainCol.isLiteralCol Then
        isNotAllLiteralCol = True
        ' 如果主列的 isSameFilter 结果已经是 False，则立刻结束
        If fieldMainCol.isSameFilter(filter) = False Then
            IDFFilterColCondition_isSameFilter = False
            Exit Function
        End If
    End If

    ' 组合两个标识位
    ' 已完成以下组合为 True:
    '   不全是字面量列
    '   非字面量的 isSameFilter 方法检查结果全部是 True --> 能到达这里说明 isSameFilter 返回的全部是 True
    IDFFilterColCondition_isSameFilter = isNotAllLiteralCol
End Function